//	websocket 结构体
package common

import (
	_ "container/list"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"time"
)

const (
	//	定义事件类型
	EventTypeMsg    = "event-msg"    // 用户发言
	EventTypeSystem = "event-system" // 系统信息推送 如房间人数
	EventTypeJoin   = "event-join"   // 用户加入
	EventTypeTyping = "event-typing" // 用户正在输入
	EventTypeLeave  = "event-leave"  // 用户离开
	EventTypeImage  = "event-image"  // todo 消息图片
)

// 用户在聊天室中的唯一ID
type Uid = string

// 发送消息的类型
type SendMsg struct {
	Type    int    `json:"type"`
	Content string `json:"content"`
}

// 回复的消息
type ReplyMsg struct {
	From    string `json:"from"`
	Code    int    `json:"code"`
	Content string `json:"content"`
}

//	聊天室
type Room struct {
	Users       map[Uid]Client // 当前房间订阅者
	UserCount   int            // 当前房间总人数
	EventChn    chan Event     // 事件通道
	JoinChn     chan Client    // 接收订阅事件的通道 用户加入聊天室后要把历史事件推送给用户
	LeaveChn    chan Uid       // 用户取消订阅通道 把通道中的历史事件释放并把用户从聊天室用户列表中删除
}

// 用户结构体
type Client struct {
	Conn 		*websocket.Conn `json:"conn"`
	RemoteAddr 	string        `json:"remote_addr"`	//	远程网络地址
	Uid 		string           `json:"uid"`			//	用户ID
	Username 	string          `json:"username"`		//	用户名
	UserEventChn    chan Event  // 事件通道
}

// 聊天室事件定义
type Event struct {
	Type      string `json:"type"`      // 事件类型	1、用户进入，2、用户退出，3、文本消息
	User      string `json:"user"`      // 用户名
	Timestamp int64  `json:"timestamp"` // 时间戳
	Text      string `json:"text"`      // 事件内容
	UserCount int    `json:"userCount"` // 房间用户数
}

// client & serve 的消息体
type Msg struct {
	Status   int             `json:"status"`
	Msg      string          `json:"msg"`
	RoomId   string          `json:"room_id"`
	Uid      string          `json:"uid"`
	Username string          `json:"username"`
	Type     string          `json:"type"`
	Data     interface{}     `json:"data"`
}

// 用户管理
type ClientManager struct {
	Clients 	map[string]*Client
	Broadcast 	chan *Broadcast
	Reply 		chan *Client
	Register 	chan *Client
	Unregister  chan *Client
}

// 广播类，包括广播内容和源用户
type Broadcast struct {
	Client 	*Client
	Message []byte
	Type 	int
}

type Rooms map[string]Room
var (
	RoomsList = make(Rooms)
	ClientMsg = Msg{}
	Manager  = ClientManager{
		Clients:    make(map[string]*Client), // 参与连接的用户，出于性能的考虑，需要设置最大连接数
		Broadcast:  make(chan *Broadcast),
		Register:   make(chan *Client),
		Reply:      make(chan *Client),
		Unregister: make(chan *Client),
	}
)

//	创建一个事件
func NewEvent(type_text string, user, msg string) Event {
	return Event{
		Type:      type_text,
		User:      user,
		Timestamp: time.Now().UnixNano() / 1e6,
		Text:      msg,
	}
}

//	读数据
func (c *Client)Read(ClientMsg Msg, RoomsList Rooms)  {
	println("进入读数据协程...")
	var Conn = c.Conn
	defer func() {
		//捕获read抛出的panic
		if err := recover(); err!=nil{
			log.Println("read发生错误", err)
			defer Conn.Close()
		}
	}()


	for  {
		println("数据读取开始...")
		//	数据读取
		_, message, err := Conn.ReadMessage()
		if err != nil {
			// 离线通知
			log.Println("ReadMessage error1", err)
			return
		}
		json.Unmarshal(message, &ClientMsg)
		println("数据读取结束...")
		println(ClientMsg.Type)
		log.Println("来自客户端的消息", ClientMsg, Conn.RemoteAddr())

		//	type：1、用户进入聊天室，2、用户退出聊天室，3、用户发言
		//	ClientMsg.Data.(map[string]interface{})["username"].(string),	//	获取data里面数据的方法
		println("消息类型：")
		println(ClientMsg.Type)
		switch ClientMsg.Type {
		case "1":	//	用户进入聊天室
			rooms_id := ClientMsg.RoomId
			r := RoomsList[rooms_id]
			r.JoinChn <- *c

		case "3":	//	聊天室消息
			rooms_id := ClientMsg.RoomId
			r := RoomsList[rooms_id]
			ev := NewEvent(EventTypeMsg, ClientMsg.Username, ClientMsg.Msg)
			r.EventChn <- ev

		}



	}
}

//	写数据
func (c *Client)Write() {
	var Conn = c.Conn
	defer func() {
		//捕获write抛出的panic
		if err := recover();err!=nil{
			log.Println("write发生错误", err)
			_ = Conn.Close()
		}
	}()
	println("进入写数据协程")
	for{
		select {
		case message, ok := <- Manager.Broadcast:
			if !ok {
				//_ = Conn.WriteMessage(websocket.CloseMessage,[]byte{})
				_ = Conn.WriteMessage(websocket.CloseMessage,[]byte{1})
				return
			}

			replyMsg := ReplyMsg{
				Code:200,
				Content:fmt.Sprintf("%s",string(message.Message)),
			}

			msg , _ := json.Marshal(replyMsg)
			_ = Conn.WriteMessage(websocket.TextMessage, msg)

		case message, ok := <- c.UserEventChn:
			println("取消息返回给用户")
			if !ok{
				_ = Conn.WriteMessage(websocket.CloseMessage,[]byte{1})
				return
			}

			replyMsg := ReplyMsg{
				Code:200,
				Content:fmt.Sprintf("%s", message.Text),
			}

			msg , _ := json.Marshal(replyMsg)
			_ = Conn.WriteMessage(websocket.TextMessage, msg)

		}

	}
}

//	处理聊天室中的事件
func (r *Room) Serve()  {
	for  {
		select {
		//	用户加入房间
		case ch := <-r.JoinChn:
			//	创建一个事件类型的通道
			println("用户加入房间通道")
			r.UserCount++	//	聊天室用户数量+1
			r.Users[ch.Uid] = ch



			//	创建系统信息推送
			ev := NewEvent(EventTypeSystem, ch.Username, "用户加入")
			ev.UserCount = r.UserCount
			fmt.Printf("%+v", ev)


			println("广播给聊天室所有用户")
			println(len(r.Users))
			//	广播给聊天室所有用户
			for _, v := range r.Users {
				println("循环...")
				fmt.Printf("%v\n", v)
				v.UserEventChn <- ev
			}
			println("广播完成")

		//	有新消息
		case ch := <- r.EventChn:
			println("有新消息进来了")
			for _, v := range r.Users {
				v.UserEventChn <- ch
			}
			println("推送完成")
			//	保存历史消息，限制保存的数量


		//	用户退出聊天室
		case ch := <- r.LeaveChn:
			if _, ok := r.Users[ch]; ok{
				delete(r.Users, ch)
				r.UserCount--
			}
		}
	}
}
